#ifndef PROGRAH
#define PROGRAH

#include <GL/glew.h>
#include <string>
#include <map>
#include "bga/graphics/GLObject.h"
#include "bga/graphics/Uniform.h"

/**
 * \namespace bga
 * \brief API namespace
 */
namespace bga
{

class Shader;

class BOARD_HELL_ENGINE Program : public GLObject
{
    private:
        Shader* vs;
        Shader* fs;
        //GLuint program;

        std::map<std::string, GLint> uniformLocations;

        void create();
        void destroy();

    public:
        Program();
        Program(Shader& vs, Shader& fs);
        virtual ~Program();

        void link();

        void setShader(Shader& shader);
        void setActive(bool active = true) const;

        void attachShader(Shader& shader);

        //GLuint getID() { return this->program; }

        int getLocation(const std::string& location);

        void setValue(const std::string& location, int value);
        void setValue(const std::string& location, float value);

        void setValues(const std::string& location, int value1, int value2);
        void setValues(const std::string& location, float value1, float value2);

        void setValues(const std::string& location, int value1, int value2, int value3);
        void setValues(const std::string& location, float value1, float value2, float value3);

        void setValues(const std::string& location, int value1, int value2, int value3, int value4);
        void setValues(const std::string& location, float value1, float value2, float value3, float value4);

        void setMatrix(const std::string& location, const float* matrix, unsigned int dimensions);

        /*!
         * \fn void setUniform() const
         * \brief Send given uniform Object to this program
         */
        void sendUniform(Uniform& uniform);

        virtual void bind() const {}
        virtual void unbind() const {}

    protected:

        virtual GLuint generate() const { return GL_NONE; }
};

}

#endif  // PROGRAH
